import { Component } from "react";
import { Application } from "./Application";
import { Observe } from "elmer-common";
import lodash from "lodash";

interface IMicroAppEvent {
    onJourneyChange: (journeys: AppView.IJourney[]) => void;
    onCurrentJourneyChange: (journey: AppView.IJourney, firstStep: AppView.IJourneyStep, option?: AppView.IMicroAppStartJourneyOption) => void;
    onCurrentJourneyStepChange: (step: AppView.IJourneyStep, state?: any) => void;
    onExitJourney: (ignoreGoHome?: boolean) => void;
}

export class MicroApp {
    public api!: Application;
    private observe: Observe<IMicroAppEvent>;
    private journeys: AppView.IJourney[] = [];
    private currentJourney?: AppView.IJourney;
    private currentStep?: AppView.IJourneyStep;
    private currentStepIndex: number = -1;
    private currentStepHistory: number[] = [];
    constructor(
        private options: AppView.IMicroAppOption
    ) {
        this.journeys = options.journeys || [];
        this.observe = new Observe();
    }
    getJourneys(): AppView.IJourney[] {
        return this.journeys || [];
    }
    createJourney(data: AppView.IJourney): void {

    }
    registeJourney(data: AppView.IJourney) {
        const exJourney = this.journeys.filter((v) => v.name === data.name)[0];
        if(exJourney) {
            console.error("the journey will registe already exists : " + data.name);
            return;
        }
        this.journeys.push(data);
        this.observe.emit("onJourneyChange", [...this.journeys]);
        return () => {
            const index = this.journeys.findIndex((v) => v.name === data.name);
            this.journeys.splice(index, 1);
            this.observe.emit("onJourneyChange", [...this.journeys]);
        };
    }
    startJourney(name: string, option?: AppView.IMicroAppStartJourneyOption): void {
        const journey = this.journeys.filter((v) => v.name === name)[0];
        this.currentJourney = journey;
        if(journey.stepJourney && journey.steps && journey.steps.length > 0) {
            this.currentStep = this.getStepData(journey.steps[0]);
            this.currentStepIndex = 0;
            this.currentStepHistory = [0];
        } else {
            this.currentStepIndex = -1;
            this.currentStepHistory = [];
        }
        this.observe.emit("onCurrentJourneyChange", journey, this.currentStep, option);
    }
    goNext(state?: any) {
        if(this.currentJourney && this.currentJourney.steps) {
            const nextIndex = this.currentStepIndex + 1;
            if(nextIndex < ((this.currentJourney.steps as unknown) as any[]).length) {
                const nextStep = this.getStepData(this.currentJourney.steps[nextIndex]);
                this.currentStep = nextStep;
                this.currentStepIndex = nextIndex;
                this.currentStepHistory.push(nextIndex);
                this.observe.emit("onCurrentJourneyStepChange", nextStep, state);
            } else {
                console.error("当前流程已结束。goto done page");
            }
        } else {
            console.error("当前没有Journey流程再运行。");
        }
    }
    goBack(state?: any) {
        if(this.currentJourney && this.currentJourney.steps) {
            const nextIndex = this.currentStepIndex - 1;
            if(nextIndex >= 0) {
                const nextStep = this.getStepData(this.currentJourney.steps[nextIndex]);
                this.currentStep = nextStep;
                this.currentStepIndex = nextIndex;
                this.currentStepHistory.push(nextIndex);
                this.observe.emit("onCurrentJourneyStepChange", nextStep, state);
            } else {
                console.error("当前流程已结束。");
                this.exitJourney();
            }
        } else {
            console.error("当前没有Journey流程再运行。");
        }
    }
    goHome() {
        if(this.currentJourney && this.currentJourney.home) {
            if(typeof this.currentJourney.home === "function") {
                this.observe.emit("onCurrentJourneyStepChange", {
                    "isMemoryPage": true,
                    Component: this.currentJourney.home
                } as AppView.IJourneyStep);
            } else {
                this.observe.emit("onCurrentJourneyStepChange", this.getStepData(this.currentJourney.home));
            }
        } else {
            console.error("Can not found the home page configuration.");
            this.observe.emit("onCurrentJourneyStepChange",null);
        }
        
    }
    on<EventName extends keyof IMicroAppEvent>(name: EventName, callback: IMicroAppEvent[EventName]) {
        return this.observe.on(name, callback);
    }
    getStepHistory() {
        const historyList = [];
        if(this.currentJourney?.steps && this.currentStepIndex >= 0 ) {
            let stepIndex = 0;
            for(let i=0;i<=this.currentStepIndex;i++) {
                const checkStep = this.getStepData(this.currentJourney.steps[i]);
                const checkStepIndex = checkStep?.index || 1;
                stepIndex += checkStepIndex;
                historyList.push({
                    index: stepIndex,
                    title: checkStep?.title,
                    id: checkStep?.id
                });
            }
        }
        return historyList;
    }
    exitJourney(ignoreGoHome?: boolean) {
        if(this.currentJourney) {
            this.currentJourney = undefined;
            this.currentStep = undefined;
            this.currentStepHistory = [];
            this.currentStepIndex = -1;
            !ignoreGoHome && this.goHome();
            this.observe.emit("onExitJourney", ignoreGoHome);
        }
    }
    /**
     * 清除临时journey
     */
    clearTempJourney() {
        const newJourneyList = [];
        for(const item of this.journeys) {
            if(!item.isTempJourney) {
                newJourneyList.push({...item});
            }
        }
        this.journeys = newJourneyList;
    }
    private getStepData(stepInfo: string|Partial<AppView.IJourneyStep>): AppView.IJourneyStep|undefined {
        if(typeof stepInfo === "string") {
            return lodash.cloneDeep(this.api.getPage(stepInfo));
        } else {
            return (stepInfo.page ? ( typeof stepInfo.page !== "string" ? {
                ...stepInfo,
                Component: stepInfo.page
            } : { ...(this.api.getPage(stepInfo.page) || {}), ...stepInfo} ) : stepInfo) as any;
        }
    }
}
